#include <libpub.h>

#define DELAY_10MS      10
#define DELAY_20MS      20
#define DELAY_100MS     100
#define DELAY_200MS     200
#define DELAY_500MS     500
#define DELAY_1000MS    1000

#define LCD_WIDTH       240
#define LCD_HEIGHT      320
#define LCD_BPP_DIS     16  // bit per pixel
//#define BASEPLANE_COLORFORMAT   COLOR_RGB565  // default

#define LCD_FULL_SIZE   (LCD_WIDTH*LCD_HEIGHT)
#define LCD_HALF_SIZE   (LCD_FULL_SIZE/2)
#define LCD_4HALF_SIZE  (LCD_FULL_SIZE/4)

//R:G:B 5:6:5
#define RED_SHIFT       11
#define GREEN_SHIFT     5
#define BLUE_SHIFT      0

#define FULL_RED        (0x1f << RED_SHIFT)
#define FULL_GREEN      (0x3f << GREEN_SHIFT)
#define FULL_BLUE       (0x1f << BLUE_SHIFT)
#define FULL_BLACK      (0x0000)

extern "C" {
int Do_InitLcd(void);
int Do_Test_Lcd(char *param);
void msleep(unsigned int ms);
void write_data_disCxt(int offset, int size, unsigned short data);
unsigned int GetBasePlaneBufAddr(void);
}

extern tCommandTbl Do_TestLcdCmdTbl[];

int DisplayBlack(void)
{
     write_data_disCxt(0, LCD_FULL_SIZE, FULL_BLACK);
     return 0;
}

int DisplayColors(UINT32 offset, int size, int step, UINT16 color, UINT32 delay)
{
    while(size > 0 && (offset + size <= LCD_FULL_SIZE)) {
         write_data_disCxt(offset, step, color);
         msleep(delay);
         offset += step;
         size -= step;
    }
    return 0;
}

int DisplayGradient(UINT16 gStart, UINT16 gEnd, UINT16 step)
{
    UINT16 c;
    for(c = gStart; c >= gStart && c <= gEnd; c += step) {
        DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, c, DELAY_20MS);
    }

    for(c = gEnd; c >= gStart && c <= gEnd; c -= step) {
        DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, c, DELAY_20MS);
    }

    return 0;
}

int _Do_Test_Lcd(char *param)
{
    TOUT(1, 1, printf("Do_Test_Lcd (\"%s\")\n", param));

    Do_InitLcd();

    if (*param) {
        DisplayBlack();
        Bo_ExeCommand(Do_TestLcdCmdTbl, param);
    }
    else {
        static tMenuTbl Do_TestLcdMenuTbl[] = {
            {'0', "Test LCD ALLMode",           "all"},
            {'1', "Test LCD in All-RedMode",    "red"},
            {'2', "Test LCD in All-GreenMode",  "green"},
            {'3', "Test LCD in All-BlueMode",   "blue"},
            {'4', "Test LCD in Gradient Mode",  "gradient"},
            {'5', "Test LCD in Priamry Color Mode", "primary"},
            {  0, MENU_NULL},       //DO NOT REMOVE
        };
        Bo_ShowMenu(Do_TestLcdMenuTbl, Do_TestLcdCmdTbl, 1);
    }

    return 0;
}

int Do_LCDTest_All(char *param)
{
    TOUT(1, 1, printf("Do_LCDTest_All(%s)", param));
    //All R G B Test
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_RED, DELAY_1000MS);
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_GREEN, DELAY_1000MS);
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_BLUE, DELAY_1000MS);
    DisplayBlack();

    //Half R G B Test
    DisplayColors(0, LCD_FULL_SIZE, LCD_HALF_SIZE, FULL_RED, DELAY_500MS);
    DisplayColors(0, LCD_FULL_SIZE, LCD_HALF_SIZE, FULL_GREEN, DELAY_500MS);
    DisplayColors(0, LCD_FULL_SIZE, LCD_HALF_SIZE, FULL_BLUE, DELAY_500MS);
    DisplayBlack();

   //4-Half R G B Test
    DisplayColors(0, LCD_FULL_SIZE, LCD_4HALF_SIZE, FULL_RED, DELAY_500MS);
    DisplayColors(0, LCD_FULL_SIZE, LCD_4HALF_SIZE, FULL_GREEN, DELAY_500MS);
    DisplayColors(0, LCD_FULL_SIZE, LCD_4HALF_SIZE, FULL_BLUE, DELAY_500MS);
    DisplayBlack();

    return 0;
}

int Do_LCDTest_R(char *param)
{
    printf("\nDo LCD Test All R:\n");
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_RED, DELAY_1000MS);
    return 0;
}

int Do_LCDTest_G(char *param)
{
    printf("\nDo LCD Test All G:\n");
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_GREEN, DELAY_1000MS);
    return 0;
}

int Do_LCDTest_B(char *param)
{
    printf("\nDo LCD Test All B:\n");
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_BLUE, DELAY_1000MS);
    return 0;
}

int Do_LCDTest_Gradient(char *param)
{
    printf("\n Do_LCDTest_Gradient()\n");
    DisplayGradient(1 << RED_SHIFT, FULL_RED, 1 << RED_SHIFT);
    DisplayGradient(1 << GREEN_SHIFT, FULL_GREEN, 1 << GREEN_SHIFT);
    DisplayGradient(1 << BLUE_SHIFT, FULL_BLUE, 1 << BLUE_SHIFT);
    return 0;
}

int Do_LCDTest_Primary(char *param)
{
    TOUT(1, 1, printf("Do_LCDTest_Primary()", param));
    UINT32 shift, step, remain;
    UINT32 g_screenWidth = LCD_WIDTH, g_screenHeight = LCD_HEIGHT;
    UINT16 *pBuf16;
    UINT32 i;

    shift = 0x8000;
    step = g_screenWidth * g_screenHeight / 16;
    remain = g_screenWidth * g_screenHeight - step * 16;
    pBuf16 = (WORD *) GetBasePlaneBufAddr();

    //Total: 16 layer: R:5,G:6,B:5
    //fill same layer with same gradient color
    for (; shift; shift >>= 1) {
             for (i = 0; i < step; i++) {
                *pBuf16 = shift;
                pBuf16++;
              }
    }

    for (i = 0; i < remain; i++) {
        *pBuf16 = shift;
        pBuf16++;
    }

    return 0;
}

tCommandTbl Do_TestLcdCmdTbl[] = {
    {Do_LCDTest_All,        "rgb",      ""},
    {Do_LCDTest_R,          "red",      ""},
    {Do_LCDTest_G,          "green",    ""},
    {Do_LCDTest_B,          "blue",     ""},
    {Do_LCDTest_Gradient,   "gradient", ""},
    {Do_LCDTest_Primary,    "primary",  ""},
    CMD_NULL,               //DO NOT REMOVE
};


//Used For LCD Backlight Test
int Display_Red_For_Backlight_Test()
{
    DisplayColors(0, LCD_FULL_SIZE, LCD_FULL_SIZE, FULL_RED, DELAY_1000MS);
    return 0;
}
